/*
 * Copyright (c) 2008, Russell Garrett
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.moneydance.modules.features.portfolioallocation;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.text.NumberFormat;
import java.util.Map;

import javax.swing.*;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieToolTipGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;

import com.moneydance.apps.md.model.CurrencyListener;
import com.moneydance.apps.md.model.CurrencyTable;
import com.moneydance.apps.md.model.RootAccount;
import com.moneydance.apps.md.view.HomePageView;
import com.moneydance.apps.md.view.gui.MoneydanceLAF;
import com.moneydance.awt.AwtUtil;
import com.moneydance.awt.JUnderlineLabel;

public class AllocationHomePageView implements HomePageView, CurrencyListener {

	@SuppressWarnings("serial")
	private class ViewPanel extends JPanel {
		private final JPanel chartPanel;
		private JFreeChart chart;
		private final JUnderlineLabel headerLabel;
		DefaultPieDataset dataset = new DefaultPieDataset();

		ViewPanel() {
			GridBagLayout gridbag = new GridBagLayout();
			this.setLayout(gridbag);
			this.setBorder(MoneydanceLAF.homePageBorder);
			this.setOpaque(false);

			Font font = getFont();
			font = new Font(font.getName(), 1, font.getSize() + 2);

			JPanel headerPanel = new JPanel(new GridBagLayout());
			headerPanel.setOpaque(false);
			// TODO: work out how to make this a JLinkLabel
			headerLabel = new JUnderlineLabel(" ", SwingConstants.LEFT);
			headerLabel.setFont(font);

			this.chartPanel = createDemoPanel();

			this.add(headerPanel, AwtUtil.getConstraints(0, 0, 0.0F, 0.0F, 1,
					1, true, true));
			headerPanel.add(headerLabel, AwtUtil.getConstraints(0, 0, 0.0F,
					0.0F, 1, 1, true, true, AwtUtil.DEFAULT_X_INSET,
					AwtUtil.DEFAULT_X_INSET, AwtUtil.DEFAULT_X_INSET,
					AwtUtil.DEFAULT_INSET));
			headerPanel.add(Box.createHorizontalStrut(2), AwtUtil
					.getConstraints(1, 0, 1.0F, 0.0F, 1, 1, true, true,
							AwtUtil.DEFAULT_X_INSET, AwtUtil.DEFAULT_INSET,
							AwtUtil.DEFAULT_X_INSET, AwtUtil.DEFAULT_INSET));
			this.add(chartPanel, AwtUtil.getConstraints(0, 1, 1.0F, 0.0F, 1, 1,
					true, true));
			this.add(Box.createVerticalStrut(2), AwtUtil.getConstraints(0, 2,
					0.0F, 1.0F, 1, 1, false, false));

			if (thisView.active) {
				this.activate();
			}
		}

		private JFreeChart createChart() {
			updateDataset();
			chart = ChartFactory.createPieChart3D(null, dataset, true, true,
					false);
			PiePlot plot = (PiePlot) chart.getPlot();
			plot.setSectionOutlinesVisible(false);
			plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 10));
			plot.setNoDataMessage("No data available");
			plot.setToolTipGenerator(new PieToolTipGenerator() {

				public String generateToolTip(PieDataset data, Comparable key) {
					RootAccount a = main.getUnprotectedContext()
							.getRootAccount();

					String pc = NumberFormat.getInstance().format(
							(float) data.getValue(key).longValue()
									/ (float) totalAllocation * 100);

					// TODO: find out how to get the configured decimal
					// character.
					return key
							+ " = "
							+ a.getCurrencyTable().getBaseType().formatFancy(
									data.getValue(key).longValue(), '.') + " ("
							+ pc + "%)";
				}

			});
			chart.setBackgroundPaint(new Color(255, 255, 255));
			return chart;
		}

		private void updateDataset() {
			dataset.clear();
			totalAllocation = 0;
			RootAccount a = main.getUnprotectedContext().getRootAccount();
			Map<String, Long> allocation = ClassifiedSecurity
					.calculateAllocation(a);

			registerListener(a);

			for (Map.Entry<String, Long> entry : allocation.entrySet()) {
				if (entry.getValue() > 0) {
					dataset.setValue(entry.getKey(), entry.getValue());
					totalAllocation += entry.getValue();
				}
			}
		}

		public JPanel createDemoPanel() {
			JFreeChart chart = createChart();
			ChartPanel cp = new ChartPanel(chart);
			cp.setPreferredSize(new Dimension(300, 250));
			return cp;
		}

		void activate() {
			refresh();
		}

		void deactivate() {

		}

		void refresh() {
			this.headerLabel.setText(thisView.toString());
			updateDataset();
		}
	}

	private final Main main;
	private boolean active = false;
	private ViewPanel view;
	private final AllocationHomePageView thisView;
	private long totalAllocation;
	private boolean listenerAdded = false;

	public AllocationHomePageView(Main main) {
		this.main = main;
		this.view = null;
		this.thisView = this;
	}

	public String getID() {
		return "portfolioallocation";
	}

	public String toString() {
		return "Portfolio Allocation";
	}

	public JComponent getGUIView(RootAccount rootAccount) {
		if (this.view == null) {
			this.view = new ViewPanel();
		}
		return this.view;
	}

	public void setActive(boolean active) {
		this.active = active;
		if (this.view != null) {
			if (active) {
				view.activate();
			} else {
				view.deactivate();
			}
		}
	}

	public void refresh() {
		if (this.view != null) {
			this.view.refresh();
		}
	}

	public synchronized void reset() {
		setActive(false);
		this.view = null;
	}

	public void registerListener(RootAccount a) {
		if (!listenerAdded) {
			a.getCurrencyTable().addCurrencyListener(this);
			listenerAdded = true;
		}
	}

	public void currencyTableModified(CurrencyTable ct) {
		refresh();
	}

}
